import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
from matplotlib import font_manager

# 确保chars目录存在
os.makedirs('chars', exist_ok=True)
os.makedirs('chars/cropped', exist_ok=True)  # 用于保存裁剪的汉字图片

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

def show_images(images, titles, rows, cols):
    plt.figure(figsize=(15, 10))
    for i in range(len(images)):
        plt.subplot(rows, cols, i + 1)
        if len(images[i].shape) == 2:
            plt.imshow(images[i], cmap='gray')
        else:
            plt.imshow(cv2.cvtColor(images[i], cv2.COLOR_BGR2RGB))
        plt.title(titles[i])
        plt.axis('off')
    plt.tight_layout()
    plt.show()

# 1. 读取原始图像
img = cv2.imread('E:\9\char-extractor\hanzi1.jpg')
if img is None:
    raise ValueError("无法读取图像文件")
original = img.copy()  # 保存原始图像的副本
cv2.imwrite('chars/1_original.jpg', img)

# 2. 灰度化处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite('chars/2_gray.jpg', gray)

# 3. 全局二值化处理（调整阈值以更好地识别汉字）
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
cv2.imwrite('chars/3_binary.jpg', binary)

# 4. 定义结构元素并增强腐蚀效果
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
eroded = cv2.erode(binary, kernel, iterations=3)  # 修改腐蚀迭代次数为3
cv2.imwrite('chars/4_eroded.jpg', eroded)

# 5. 对腐蚀后的图像进行适当的膨胀操作
dilated = cv2.dilate(eroded, kernel, iterations=12)  # 修改膨胀迭代次数为12
cv2.imwrite('chars/5_dilated.jpg', dilated)

# 6. 使用大型十字形结构元素进行闭运算处理
kernel_closing = cv2.getStructuringElement(cv2.MORPH_CROSS, (25, 25))
closing = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, kernel_closing)
closing = cv2.morphologyEx(closing, cv2.MORPH_CLOSE, kernel_closing)
cv2.imwrite('chars/6_closing.jpg', closing)

# 7. 对闭运算后的图像进行边缘检测
blurred = cv2.GaussianBlur(closing, (7, 7), 0)
edges = cv2.Canny(blurred, 30, 150)
cv2.imwrite('chars/7_edges.jpg', edges)

# 8. 寻找轮廓并基于周长筛选（检测每个汉字）
contours, hierarchy = cv2.findContours(closing, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 创建用于显示轮廓检测结果的图像
contours_img = cv2.cvtColor(closing, cv2.COLOR_GRAY2BGR)
result_img = original.copy()  # 用于在原图上绘制最终结果

# 9. 遍历所有轮廓，检测每个汉字并绘制正外接矩形边框
print("\n检测到的汉字轮廓信息：")
detected_chars = 0

# 调整轮廓检测参数
min_perimeter = 200  # 最小周长阈值，根据实际图像调整
max_perimeter = 5000  # 最大周长阈值，根据实际图像调整
min_aspect = 0.3  # 最小宽高比
max_aspect = 3.0  # 最大宽高比

for i, contour in enumerate(contours):
    # 计算轮廓周长
    perimeter = cv2.arcLength(contour, True)
    
    # 过滤周长不在范围内的轮廓
    if min_perimeter < perimeter < max_perimeter:
        # 获取正外接矩形
        x, y, w, h = cv2.boundingRect(contour)
        
        # 计算宽高比，排除不规则形状
        aspect_ratio = w / h
        if min_aspect < aspect_ratio < max_aspect:
            detected_chars += 1
            
            # 在轮廓图上绘制正外接矩形
            cv2.rectangle(contours_img, (x, y), (x + w, y + h), (0, 255, 0), 2)
            
            # 在原图上绘制正外接矩形
            cv2.rectangle(result_img, (x, y), (x + w, y + h), (0, 255, 0), 2)
            
            # 截取矩形区域并保存为PNG文件
            roi = original[y:y+h, x:x+w]
            save_path = f"chars/cropped/char_{detected_chars}.png"
            cv2.imwrite(save_path, roi)
            
            print(f"汉字 {detected_chars}: 位置=({x}, {y}), 尺寸=({w}x{h}), 周长={perimeter:.2f}, 已保存至 {save_path}")

# 保存结果
cv2.imwrite('chars/8_contours.jpg', contours_img)
cv2.imwrite('chars/9_final_result.jpg', result_img)

# 显示处理步骤的结果
images = [original, binary, eroded, dilated, 
          closing, edges, contours_img, result_img]
titles = ['原始图像', '二值化', '腐蚀', '膨胀', 
          '闭运算', 'Canny边缘', '正外接矩形', '最终结果']
show_images(images, titles, 3, 12)

# 打印保存的文件信息
print("\n已保存的处理结果：")
print("1. chars/1_original.jpg - 原始图像")
print("2. chars/2_gray.jpg - 灰度图像")
print("3. chars/3_binary.jpg - 二值化图像")
print("4. chars/4_eroded.jpg - 腐蚀处理")
print("5. chars/5_dilated.jpg - 膨胀")
print("6. chars/6_closing.jpg - 闭运算")
print("7. chars/7_edges.jpg - Canny边缘检测")
print("8. chars/8_contours.jpg - 正外接矩形边框")
print("9. chars/9_final_result.jpg - 最终结果")
print(f"10. chars/cropped/ - 已保存 {detected_chars} 个汉字截图")